﻿// 这段 MFC 示例源代码演示如何使用 MFC Microsoft Office Fluent 用户界面 
// (“Fluent UI”)。该示例仅供参考，
// 用以补充《Microsoft 基础类参考》和 
// MFC C++ 库软件随附的相关电子文档。  
// 复制、使用或分发 Fluent UI 的许可条款是单独提供的。  
// 若要了解有关 Fluent UI 许可计划的详细信息，请访问 
// https://go.microsoft.com/fwlink/?LinkId=238214.
//
// 版权所有(C) Microsoft Corporation
// 保留所有权利。

#include "pch.h"
#include "framework.h"
#include "MainFrm.h"
#include "ClassView.h"
#include "Resource.h"
#include "DBBrowser.h"
#include "DBBrowserDoc.h"
#include "DBBrowserView.h"

//////////////////////////////////////////////////////////////////////
// 构造/析构
//////////////////////////////////////////////////////////////////////

CClassView::CClassView() noexcept
{
	m_nCurrSort = ID_SORTING_GROUPBYTYPE;
}

CClassView::~CClassView()
{
}

BEGIN_MESSAGE_MAP(CClassView, CDockablePane)
	ON_WM_CREATE()
	ON_WM_SIZE()
	ON_WM_CONTEXTMENU()
	ON_WM_PAINT()
	ON_WM_SETFOCUS()
	ON_NOTIFY(TVN_SELCHANGED, ID_VIEW_CLASSVIEW2, OnSelChanged)
	ON_COMMAND(ID_TB_DROP, &CClassView::OnTbDrop)
	ON_COMMAND(ID_TB_CLEAR, &CClassView::OnTbClear)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CClassView 消息处理程序

int CClassView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CDockablePane::OnCreate(lpCreateStruct) == -1)
		return -1;

	CRect rectDummy;
	rectDummy.SetRectEmpty();

	// 创建视图: 
	const DWORD dwViewStyle = WS_CHILD | WS_VISIBLE | TVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TVS_SHOWSELALWAYS;
	if (!m_wndClassView.Create(dwViewStyle, rectDummy, this, ID_VIEW_CLASSVIEW2))
	{
		TRACE0("未能创建类视图\n");
		return -1;      // 未能创建
	}

	OnChangeVisualStyle();
	return 0;
}

void CClassView::OnSize(UINT nType, int cx, int cy)
{
	CDockablePane::OnSize(nType, cx, cy);
	AdjustLayout();
}

void CClassView::OnContextMenu(CWnd* pWnd, CPoint point)
{
	CViewTree* pWndTree = (CViewTree*)&m_wndClassView;
	ASSERT_VALID(pWndTree);

	if (pWnd != pWndTree)
	{
		CDockablePane::OnContextMenu(pWnd, point);
		return;
	}

	if (point != CPoint(-1, -1))
	{
		// 选择已单击的项: 
		CPoint ptTree = point;
		pWndTree->ScreenToClient(&ptTree);

		UINT flags = 0;
		HTREEITEM hTreeItem = pWndTree->HitTest(ptTree, &flags);
		if (hTreeItem != nullptr)
		{
			pWndTree->SelectItem(hTreeItem);
		}
	}

	pWndTree->SetFocus();
	if (GetDepth(pWndTree->GetSelectedItem()) == 2){
		if (m_wndClassView.GetItemText(m_wndClassView.GetParentItem(pWndTree->GetSelectedItem())) == L"表") {
			theApp.GetContextMenuManager()->ShowPopupMenu(IDR_POPUP_EXPLORER, point.x, point.y, this, TRUE);
		}
		else if (m_wndClassView.GetItemText(m_wndClassView.GetParentItem(pWndTree->GetSelectedItem())) == L"索引") {
			theApp.GetContextMenuManager()->ShowPopupMenu(IDR_POPUP_EXPLORER, point.x, point.y, this, TRUE);
		}
	}
}

void CClassView::AdjustLayout()
{
	if (GetSafeHwnd() == nullptr)
	{
		return;
	}

	CRect rectClient;
	GetClientRect(rectClient);

	//int cyTlb = m_wndToolBar.CalcFixedLayout(FALSE, TRUE).cy;

	//m_wndToolBar.SetWindowPos(nullptr, rectClient.left, rectClient.top, rectClient.Width(), cyTlb, SWP_NOACTIVATE | SWP_NOZORDER);
	m_wndClassView.SetWindowPos(nullptr, rectClient.left + 1, rectClient.top + 1, rectClient.Width() - 2, rectClient.Height() - 2, SWP_NOACTIVATE | SWP_NOZORDER);
}

BOOL CClassView::PreTranslateMessage(MSG* pMsg)
{
	return CDockablePane::PreTranslateMessage(pMsg);
}


void CClassView::OnPaint()
{
	CPaintDC dc(this); // 用于绘制的设备上下文

	CRect rectTree;
	m_wndClassView.GetWindowRect(rectTree);
	ScreenToClient(rectTree);

	rectTree.InflateRect(1, 1);
	dc.Draw3dRect(rectTree, ::GetSysColor(COLOR_3DSHADOW), ::GetSysColor(COLOR_3DSHADOW));
}

void CClassView::OnSetFocus(CWnd* pOldWnd)
{
	CDockablePane::OnSetFocus(pOldWnd);

	m_wndClassView.SetFocus();
}

void CClassView::OnChangeVisualStyle()
{
	m_ClassViewImages.DeleteImageList();

	UINT uiBmpId = theApp.m_bHiColorIcons ? IDB_CLASS_VIEW_24 : IDB_CLASS_VIEW;

	CBitmap bmp;
	if (!bmp.LoadBitmap(uiBmpId))
	{
		TRACE(_T("无法加载位图: %x\n"), uiBmpId);
		ASSERT(FALSE);
		return;
	}

	BITMAP bmpObj;
	bmp.GetBitmap(&bmpObj);

	UINT nFlags = ILC_MASK;

	nFlags |= (theApp.m_bHiColorIcons) ? ILC_COLOR24 : ILC_COLOR4;

	m_ClassViewImages.Create(16, bmpObj.bmHeight, nFlags, 0, 0);
	m_ClassViewImages.Add(&bmp, RGB(255, 0, 0));

	m_wndClassView.SetImageList(&m_ClassViewImages, TVSIL_NORMAL);
}

void CClassView::OnSelChanged(NMHDR *pNMHDR, LRESULT *pResult)
{
	// TODO: 在此处添加实现代码.
	LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
	HTREEITEM hPa = nullptr;
	if (GetDepth(pNMTreeView->itemNew.hItem) == 2
		&& m_wndClassView.GetItemText(hPa = m_wndClassView.GetParentItem(pNMTreeView->itemNew.hItem)) == L"表") {
		CMFCRibbonBar *pRibbon = ((CMainFrame*)AfxGetMainWnd())->GetRibbonBar();
		CMFCRibbonEdit *edit = DYNAMIC_DOWNCAST(CMFCRibbonEdit, pRibbon->FindByID(ID_SEARCHEDIT));
		ASSERT_VALID(edit);
		edit->SetEditText(_T(""));
		CString strSelItem = m_wndClassView.GetItemText(pNMTreeView->itemNew.hItem);
		CString strRoot = m_wndClassView.GetItemText(m_wndClassView.GetParentItem(hPa));
		CString sql = _T("select _rowid_,* from '" + strRoot + "'.'" + strSelItem + "' ");
		CDBBrowserDoc *pDoc = (CDBBrowserDoc*)((CFrameWndEx*)AfxGetApp()->m_pMainWnd)->GetActiveDocument();
		CDBBrowserView *pView = (CDBBrowserView*)((CFrameWndEx*)AfxGetApp()->m_pMainWnd)->GetActiveView();
		pView->m_focus.changed = false;
		pView->m_focus.iItem = -1;
		pView->m_focus.iSubItem = 0;
		pView->UpdateRichEdit();
		try {
			pDoc->m_sql_select = sqlite::utility::utf16_to_utf8(sql.GetString());
			pDoc->databaseadapter(pDoc->m_sql_select);
			pDoc->SetTitle(strSelItem);
			pDoc->m_table = _T("'") + strRoot + _T("'.'") + strSelItem + _T("'");
			pDoc->m_root = strRoot;
			pDoc->m_tbl = strSelItem;
		}
		catch (sqlite::sqlite_exception& e){
			MessageBoxA(*GetParent(), e.get_msg(), 0, 0);
		}
	}
}

int CClassView::GetDepth(HTREEITEM hTreeItem)
{
	// TODO: 在此处添加实现代码.
	int nCount = -1;
	while (hTreeItem != NULL)
	{
		hTreeItem = m_wndClassView.GetParentItem(hTreeItem);
		nCount++;
	}	
	return nCount;
}


void CClassView::OnTbDrop()
{
	// TODO: 在此添加命令处理程序代码
	CDBBrowserDoc *pDoc = (CDBBrowserDoc*)((CFrameWndEx*)AfxGetMainWnd())->GetActiveDocument();
	CDBBrowserView *pView = (CDBBrowserView*)((CFrameWndEx*)AfxGetMainWnd())->GetActiveView();
	try {
		if (pDoc->m_autotrans && !pDoc->m_transaction) {
			pDoc->m_db << "begin;";
			pDoc->m_transaction = true;
		}
		CString type = m_wndClassView.GetItemText(m_wndClassView.GetParentItem(m_wndClassView.GetSelectedItem()));
		if (type == _T("表")) {
			pDoc->m_db << (L"drop table " + pDoc->m_table).GetString();
			pDoc->Cleartblinfo();
			pView->m_List.SetRedraw(FALSE);
			pDoc->SetTitle(_T(""));
			pView->m_List.SetItemCount(0);
			pView->m_List.SetRedraw(TRUE);
			for (int i = 0; i < pDoc->m_columncount; i++) { pView->m_List.DeleteColumn(0); }
			auto pStatusBar = (CMFCRibbonStatusBar*)((CFrameWndEx*)AfxGetMainWnd())->GetPane(AFX_IDW_STATUS_BAR);
			auto pStatusBarPane = (CMFCRibbonStatusBarPane*)(pStatusBar->FindElement(ID_STATUSBAR_PANE2));
			pStatusBarPane->SetText(_T("共0条"));
			pStatusBarPane->Redraw();
			ReBuildTree();
			pView->UpdateRichEdit();
		}
		else {
			CString d = m_wndClassView.GetItemText(m_wndClassView.GetParentItem(m_wndClassView.GetParentItem(m_wndClassView.GetSelectedItem())));
			CString i = m_wndClassView.GetItemText(m_wndClassView.GetSelectedItem());
			CString sql; sql.Format(_T("drop index '%s'.'%s'"), d, i);
			pDoc->m_db << sql;
			ReBuildTree();
			HTREEITEM node = m_wndClassView.GetRootItem();
			while (node && m_wndClassView.GetItemText(node) != d) { node = m_wndClassView.GetNextItem(node, TVGN_NEXT); }
			if (node) { node = m_wndClassView.GetNextItem(node, TVGN_CHILD); }
			while (node && m_wndClassView.GetItemText(node) != _T("索引")) { node = m_wndClassView.GetNextItem(node, TVGN_NEXT); }
			if (node) { m_wndClassView.Expand(node, TVE_EXPAND); }
		}
	}
	catch (sqlite::sqlite_exception& e) {
		MessageBoxA(*GetParent(), e.get_msg(), 0, 0);
	}
}


void CClassView::OnTbClear()
{
	// TODO: 在此添加命令处理程序代码
	CDBBrowserDoc *pDoc = (CDBBrowserDoc*)((CFrameWndEx*)AfxGetMainWnd())->GetActiveDocument();
	try {
		if (pDoc->m_autotrans && !pDoc->m_transaction) {
			pDoc->m_db << "begin;";
			pDoc->m_transaction = true;
		}
		pDoc->m_db << (L"delete from " + pDoc->m_table).GetString();
		pDoc->databaseadapter(pDoc->m_sql, false);
		CDBBrowserView *pView = (CDBBrowserView*)((CFrameWndEx*)AfxGetMainWnd())->GetActiveView();
		pView->UpdateRichEdit();
	}
	catch (sqlite::sqlite_exception& e) {
		MessageBoxA(*GetParent(), e.get_msg(), 0, 0);
	}
}


void CClassView::ReBuildTree()
{
	// TODO: 在此处添加实现代码.
	CDBBrowserDoc *pDoc = (CDBBrowserDoc*)((CFrameWndEx*)AfxGetMainWnd())->GetActiveDocument();
	pDoc->m_tree.clear();
	m_wndClassView.SetRedraw(FALSE);
	m_wndClassView.DeleteAllItems();
	pDoc->m_db << "PRAGMA database_list;" >> [&](std::wstring seq, std::wstring database) {
		HTREEITEM hRoot = m_wndClassView.InsertItem(database.data(), 2, 2);
		HTREEITEM hTable = m_wndClassView.InsertItem(_T("表"), 0, 0, hRoot);
		HTREEITEM hIndex = m_wndClassView.InsertItem(_T("索引"), 0, 0, hRoot);
		std::vector<std::wstring> tbls; bool hastable = false;
		pDoc->m_tree[database.data()] = tbls;
		pDoc->m_db << std::wstring(L"select type,name from '") + database + std::wstring(L"'.sqlite_master ORDER by tbl_name")
			>> [&](std::wstring type,std::wstring name) {
			if (type == L"table") {
				pDoc->m_tree[database.data()].push_back(name);
				HTREEITEM node = m_wndClassView.InsertItem(name.data(), 5, 5, hTable);
				pDoc->m_db << L"PRAGMA '" + CString(database.data()) + L"'.table_info('" + CString(name.data()) + L"')" >> [&](std::wstring s1, std::wstring s2, std::wstring s3) {
					m_wndClassView.InsertItem((s2 + L"(" + s3 + L")").data(), 6, 6, node);
				};
			}
			else {
				HTREEITEM node = m_wndClassView.InsertItem(name.data(), 3, 3, hIndex);
				pDoc->m_db << L"PRAGMA '" + CString(database.data()) + L"'.index_info('" + CString(name.data()) + L"')" >> [&](std::wstring s1, std::wstring s2, std::wstring s3) {
					m_wndClassView.InsertItem(s3.data(), 4, 4, node);
				};
			}
			hastable = true;
		};
		if (hastable) {
			m_wndClassView.Expand(hRoot, TVE_EXPAND);
			m_wndClassView.Expand(hTable, TVE_EXPAND);
		}
		else {
			m_wndClassView.DeleteItem(hRoot);
		}
	};
	m_wndClassView.SetRedraw(TRUE);
}
